package cn.ckx.coding.common.utils;

import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Consumer;

import cn.ckx.coding.common.annotation.excel.ExcelCell;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.lang.NonNull;


/**
 * @ClassName ExcelUtils
 * @Description
 * 
 * excel 处理类
 * 
 * @Author kunxin.cai
 * @Date 2021/4/17
 * @Version 1.0
 **/
@Slf4j
public class ExcelUtils {

    /**
     * 读取excel，转换成指定对象数组
     * 
     * @param objClass 转换类
     * @param consumer 实例处理
     * @param file excel文件
     * @param hasTotal 是否拥有表头
     * @return List<T> 结果
     */
    public static <T> List<T> readExcel(@NonNull File file, boolean hasTotal, @NonNull Class<T> objClass, Consumer<T> consumer) {
        List<T> data = new ArrayList<>();
        Map<String, Integer> fieldMaps = Maps.newHashMap();
        
        for (Field field : objClass.getDeclaredFields()) {
            ExcelCell annotation = field.getDeclaredAnnotation(ExcelCell.class);
            if (annotation != null) {
                fieldMaps.put(field.getName(), annotation.col());
            }
        }
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            XSSFWorkbook workbook = new XSSFWorkbook(fileInputStream);
            Iterator<Row> rowIterator = workbook.getSheetAt(0).rowIterator();
            if (hasTotal && rowIterator.hasNext()) {
                rowIterator.next();
            }
            
            while (rowIterator.hasNext()) {
                T t = objClass.newInstance();
                fieldMaps.keySet().forEach(item -> {
                    Row row = rowIterator.next();
                    try {
                        Field declaredField = objClass.getDeclaredField(item);
                        declaredField.setAccessible(true);
                        Cell cell = row.getCell(fieldMaps.get(item));
                        Object objValue = cellParseValue(cell, declaredField);
                        declaredField.set(t, objValue);
                    } catch (NoSuchFieldException | IllegalAccessException e) {
                        log.error("error: 【{}】，msg：【{}】，stackTrace：【{}】", e.getClass(), e.getMessage(), e.getStackTrace());
                    } catch (IllegalStateException e) {
                        log.error("row:【{}】,cell:【{}】, data type error", row.getRowNum(), fieldMaps.get(item));
                    }
                });
                
                if (consumer != null) {
                    consumer.accept(t);
                }
                
                data.add(t);  
            }
           Double a; 
        } catch (IOException | InstantiationException  | IllegalAccessException e) {
            log.error("error: 【{}】，msg：【{}】，stackTrace：【{}】", e.getClass(), e.getMessage(), e.getStackTrace());    
        }
        return data;
    }
    
    private static Object cellParseValue(Cell cell, Field field) {
        switch (String.valueOf(field.getGenericType())) {
            case "class java.lang.Integer": return (int)cell.getNumericCellValue();
            case "class java.lang.Double": return cell.getNumericCellValue();
            case "class java.lang.Boolean": return cell.getBooleanCellValue();
            case "class java.lang.Date": return cell.getDateCellValue();
            case "class java.time.LocalDateTime": return cell.getLocalDateTimeCellValue();
            default: return cell.toString();
        }
    }

}
                                            